package com.hy.frame.mvvm.state

import androidx.lifecycle.MutableLiveData
import com.hy.frame.mvvm.net.AppException
import com.hy.frame.mvvm.net.BaseResponse
import com.hy.frame.mvvm.net.ExceptionHandle
import java.util.concurrent.CancellationException

/**
 * 结果
 */
sealed class ResultState<out T> {
    /**
     * 请求标识
     */
    var flag: String? = null

    data class Loading(val loadingMessage: String?) : ResultState<Nothing>()
    data class Success<out T>(val data: T) : ResultState<T>()
    data class Error(val error: AppException) : ResultState<Nothing>()
    companion object {
        fun <T> newLoading(msg: String?): ResultState<T> = Loading(msg)
        fun <T> newSuccess(data: T): ResultState<T> = Success(data)
        fun <T> newError(error: AppException): ResultState<T> = Error(error)
    }
}

/**
 * 处理返回值
 * @param result 请求结果
 * @param flag 请求标识 可空
 */
fun <T> MutableLiveData<ResultState<T>>.handle(result: BaseResponse<T>, flag: String? = null) {
    val rst: ResultState<T> = if (result.isSuccess())
        ResultState.newSuccess(result.getResponseData())
    else
        ResultState.newError(AppException(result.getResponseCode(), result.getResponseMsg()))
    rst.flag = flag
    value = rst
}

/**
 * 不处理返回值 直接返回请求结果
 * @param result 请求结果
 * @param flag 请求标识 可空
 */
fun <T> MutableLiveData<ResultState<T>>.handle(result: T, flag: String? = null) {
    val rst: ResultState<T> = ResultState.newSuccess(result)
    rst.flag = flag
    value = rst
}

/**
 * 异常转换异常处理
 */
fun <T> MutableLiveData<ResultState<T>>.handleException(e: Throwable, flag: String? = null) {
    if (e is CancellationException) {//主动取消请求 拦截错误提示
        return
    }
    val error = ExceptionHandle.handleException(e)
    val rst: ResultState<T> = ResultState.newError(error)
    rst.flag = flag
    value = rst
}


/**
 * 解析结果
 */
fun <T> ResultState<T>.with(
    onSuccess: (T) -> Unit,
    onError: ((AppException) -> Unit)? = null,
    onLoading: ((Boolean, String?) -> Unit)? = null
) {
    when (this) {
        is ResultState.Loading -> {
            onLoading?.invoke(true, this.loadingMessage)
        }
        is ResultState.Success -> {
            onLoading?.invoke(false, null)
            onSuccess.invoke(this.data)
        }
        is ResultState.Error -> {
            onLoading?.invoke(false, null)
            onError?.invoke(this.error)
        }
    }
}